--[[
描述 ：XML  解析xml   生成xml
作者 ： 付大志
时间 ： 14/0/26
]]

Xml = {}

Xml.xmlText ='<?xml version=\"1.0\" encoding=\"utf-8\"?>';

function Xml.ToXmlString(value)
  value = string.gsub (value, "&", "&amp;");		-- '&' -> "&amp;"
  value = string.gsub (value, "<", "&lt;");		-- '<' -> "&lt;"
  value = string.gsub (value, ">", "&gt;");		-- '>' -> "&gt;"
  value = string.gsub (value, "\"", "&quot;");	-- '"' -> "&quot;"
  value = string.gsub(value, "([^%w%&%;%p%\t% ])",
    function (c)
      return string.format("&#x%X;", string.byte(c))
    end);
  return value;
end

function Xml.FromXmlString(value)
  value = string.gsub(value, "&#x([%x]+)%;",
    function(h)
      return string.char(tonumber(h,16))
    end);
  value = string.gsub(value, "&#([0-9]+)%;",
    function(h)
      return string.char(tonumber(h,10))
    end);
  value = string.gsub (value, "&quot;", "\"");
  value = string.gsub (value, "&apos;", "'");
  value = string.gsub (value, "&gt;", ">");
  value = string.gsub (value, "&lt;", "<");
  value = string.gsub (value, "&amp;", "&");
  return value;
end

function Xml.ParseArgs(s)
  local arg = {}
  string.gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a)
    arg[w] = Xml.FromXmlString(a);
  end)
  return arg
end

--[[
功能   ： 解析xml文本 生成table
参数   ： xmlText --- 文本
返回   ： xml  table
注      ：   table格式 {"name":"auhtor","child":[],"properties":[],"value":"22"}
]]
function Xml.parse(xmlText)
  if xmlText  == nil then
   print('ParseXmlText==nil');
  end
  local stack = {}
  local namespace = {}
  local labelNamespace = nil
  local top = {name=nil,value=nil,properties={},child={}, namespace=nil}
  table.insert(stack, top)
  local ni,c,label,xarg, empty
  local i, j = 1, 1
  local namespaceIndex = 1
  while true do
    ni,j,c,label,xarg, empty = string.find(xmlText, "<(%/?)([%w:]+)(.-)(%/?)>", i)
    if not ni then break end
    local text = string.sub(xmlText, i, ni-1);
    if not string.find(text, "^%s*$") then
      top.value=(top.value or "")..Xml.FromXmlString(text);
    end
    namespaceIndex = 1
    while true do
      namespaceIndex = string.find(xarg, "xmlns:", namespaceIndex)
      if not namespaceIndex then break end
      local equalSign = string.find(xarg, "=", namespaceIndex)
      local nsName = string.sub(xarg, namespaceIndex + 6, equalSign -1)
      local endNS = string.find(xarg, "\" ", equalSign + 2)
      namespace[nsName] = string.sub(xarg, equalSign + 1, endNS + 1)
      -- print("Name space: " .. nsName .. ":" ..namespace[nsName])
      namespaceIndex = equalSign
    end
    -- ditch name space
    if label then
      local matchcount = 0
      -- walk through our namespace table nuking it as we go
      for k in pairs(namespace) do
        label, matchcount = string.gsub(label, k..":", "");
        if matchcount >= 1 then
          labelNamespace = k
        else
          labelNamespace = nil
        end
      end
    end
    if empty == "/" then  -- empty element tag
      table.insert(top.child, {name=label,value=nil,properties=Xml.ParseArgs(xarg),child={}})
    elseif c == "" then   -- start tag
      top = {name=label, value=nil, properties=Xml.ParseArgs(xarg), child={}, namespace=labelNamespace}
      table.insert(stack, top)   -- new level
    else  -- end tag
      local toclose = table.remove(stack)  -- remove top
      top = stack[#stack]
      if #stack < 1 then
        error("Xml: nothing to close with "..label)
      end
      if toclose.name ~= label then
        error("Xml: trying to close "..toclose.name.." with "..label)
      end
      table.insert(top.child, toclose)
    end
    i = j+1
  end
  local text = string.sub(xmlText, i);
  if not string.find(text, "^%s*$") then
    stack[#stack].value=(stack[#stack].value or "")..Xml.FromXmlString(text);
  end
  if #stack > 1 then
    error("Xml: unclosed "..stack[stack.n].name)
  end
  stack[1].child[1].namespace = namespace
  return stack[1].child[1];
end



--[[
功能   ： 根据table生成xml
参数   ： xmlTable --- xml  table
返回   ： xml 字符串
注      ：   table格式 {"name":"auhtor","child":[],"properties":["text":"Execute!"],"value":"22"}
]]

function Xml.gen(xmlTable)
  Xml.xmlText =  Xml.xmlText..'<'
  if  xmlTable.name == nil then
    print('error Xml->name =nil ')
  end
  if  type(xmlTable.name) ~= "string" then
    print('error Xml->name != string ')
  end
  Xml.xmlText= Xml.xmlText..xmlTable.name..' ';
 
  if xmlTable.properties ~=  nil then
    for key, var in pairs(xmlTable.properties) do
      Xml.xmlText =Xml.xmlText..key..'='..'\"'..var..'\"'..' ';
    end
    Xml.xmlText =Xml.xmlText..'>';
  end

  for key, var in ipairs(xmlTable.child) do
     Xml.xmlText =  Xml.xmlText..'\n'
     Xml.gen(var)
  end

  if xmlTable.value ~= nil  then
     Xml.xmlText = Xml.xmlText..xmlTable.value;
  end
   Xml.xmlText = Xml.xmlText..'\n'..'</'..xmlTable.name..'>';
  return Xml.xmlText;
end
